package com.getpebble.android.framework.endpoint;

import android.os.Handler;
import android.os.Looper;
import com.getpebble.android.R;
import com.getpebble.android.bluetooth.protocol.ProtocolMessage;
import com.getpebble.android.common.core.trace.Trace;
import com.getpebble.android.common.framework.install.PutBytesType;
import com.getpebble.android.common.model.FrameworkState;
import com.getpebble.android.framework.install.Stm32Crc;
import com.getpebble.android.framework.protocol.EndpointId;
import com.getpebble.android.framework.protocol.inbound.PblInboundPutBytesMessage;
import com.getpebble.android.framework.protocol.inbound.PblInboundPutBytesMessage.PutBytesResponse;
import com.getpebble.android.framework.protocol.outbound.PblOutboundPutBytesMessage;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.UnsignedInteger;
import com.sun.mail.imap.protocol.ListInfo;
import com.sun.mail.smtp.SMTPMessage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;

public class PutBytesEndpoint extends RequestableEndpoint {
    private static final String TAG = PutBytesEndpoint.class.getSimpleName();
    private State mAbortedState = null;
    private int mAppBank;
    private UnsignedInteger mBytesTransferred = UnsignedInteger.fromIntBits(0);
    private UnsignedInteger mCookie;
    private UnsignedInteger mExpectedCrc;
    private Handler mHander;
    private InputStream mInputStream;
    private InstallResult mInstallResult;
    private PutBytesType mInstallType;
    private Listener mListener = null;
    private IEndpointMessageSender mMessageSender;
    private String mName;
    private Runnable mResponseTimeoutRunnable = new Runnable() {
        public void run() {
            PutBytesEndpoint.this.mInstallResult = InstallResult.TIMEOUT;
            if (PutBytesEndpoint.this.mState != State.CANCELLED) {
                Trace.debug(PutBytesEndpoint.TAG, "Wait for messages expired, aborting.");
                PutBytesEndpoint.this.abortTransfer();
                return;
            }
            Listener listener = PutBytesEndpoint.this.getListener();
            if (listener != null) {
                listener.transferFailed(PutBytesEndpoint.this.mInstallResult);
            }
            PutBytesEndpoint.this.cleanup();
        }
    };
    private UnsignedInteger mSize;
    private State mState = State.IDLE;
    private Stm32Crc mStm32Crc = null;

    interface Listener {
        void installComplete(UnsignedInteger unsignedInteger);

        void installFailed(InstallResult installResult);

        void progressUpdated(UnsignedInteger unsignedInteger, UnsignedInteger unsignedInteger2);

        void transferComplete(UnsignedInteger unsignedInteger);

        void transferFailed(InstallResult installResult);
    }

    static /* synthetic */ class AnonymousClass2 {
        static final /* synthetic */ int[] $SwitchMap$com$getpebble$android$framework$endpoint$PutBytesEndpoint$State = new int[State.values().length];

        static {
            try {
                $SwitchMap$com$getpebble$android$framework$endpoint$PutBytesEndpoint$State[State.WAITING_FOR_COOKIE.ordinal()] = 1;
            } catch (NoSuchFieldError e) {
            }
            try {
                $SwitchMap$com$getpebble$android$framework$endpoint$PutBytesEndpoint$State[State.SENDING_DATA.ordinal()] = 2;
            } catch (NoSuchFieldError e2) {
            }
            try {
                $SwitchMap$com$getpebble$android$framework$endpoint$PutBytesEndpoint$State[State.COMMIT_SENT.ordinal()] = 3;
            } catch (NoSuchFieldError e3) {
            }
            try {
                $SwitchMap$com$getpebble$android$framework$endpoint$PutBytesEndpoint$State[State.CANCELLED.ordinal()] = 4;
            } catch (NoSuchFieldError e4) {
            }
            try {
                $SwitchMap$com$getpebble$android$framework$endpoint$PutBytesEndpoint$State[State.INSTALLING.ordinal()] = 5;
            } catch (NoSuchFieldError e5) {
            }
        }
    }

    public enum InstallResult {
        OK,
        CANCELLED,
        INSTALL_FAILED,
        LOAD_FAILED,
        ACK_FAILED,
        INVALID_CRC,
        TIMEOUT,
        UNKNOWN_ERROR
    }

    private enum State {
        IDLE,
        WAITING_FOR_COOKIE,
        SENDING_DATA,
        COMMIT_SENT,
        WAITING_FOR_INSTALL,
        CANCELLED,
        INSTALLING
    }

    boolean onRequest(EndpointRequest request, FrameworkState frameworkState) {
        return false;
    }

    boolean onPrfRequest(EndpointRequest request, FrameworkState frameworkState) {
        return false;
    }

    public PutBytesEndpoint(IEndpointMessageSender messageSender) {
        if (messageSender == null) {
            throw new IllegalArgumentException("'messageSender' cannot be null!");
        }
        this.mMessageSender = messageSender;
        this.mHander = new Handler(Looper.getMainLooper());
    }

    public PutBytesEndpoint setInputStream(InputStream inputStream) {
        this.mInputStream = inputStream;
        return this;
    }

    public PutBytesEndpoint setName(String name) {
        this.mName = name;
        return this;
    }

    public PutBytesEndpoint setSize(int size) {
        this.mSize = UnsignedInteger.fromIntBits(size);
        return this;
    }

    public PutBytesEndpoint setExpectedCrc(UnsignedInteger expectedCrc) {
        this.mExpectedCrc = expectedCrc;
        return this;
    }

    public PutBytesEndpoint setAppBank(int appBank) {
        this.mAppBank = appBank;
        return this;
    }

    public PutBytesEndpoint setInstallType(PutBytesType installType) {
        this.mInstallType = installType;
        return this;
    }

    public synchronized boolean lock(Listener listener) {
        boolean z = true;
        synchronized (this) {
            if (this.mListener != listener) {
                if (this.mListener != null) {
                    z = false;
                } else {
                    this.mListener = listener;
                }
            }
        }
        return z;
    }

    public synchronized boolean unlock(Listener listener) {
        boolean z = false;
        synchronized (this) {
            if (this.mListener != null) {
                if (this.mListener == listener) {
                    this.mListener = null;
                    cleanup();
                    z = true;
                }
            }
        }
        return z;
    }

    private IEndpointMessageSender getMessageSender() {
        return this.mMessageSender;
    }

    private Listener getListener() {
        return this.mListener;
    }

    protected void startTimeout() {
        this.mHander.postDelayed(this.mResponseTimeoutRunnable, 60000);
    }

    private void cancelTimeout() {
        this.mHander.removeCallbacks(this.mResponseTimeoutRunnable);
    }

    public void startTransfer() {
        this.mStm32Crc = new Stm32Crc();
        this.mBytesTransferred = UnsignedInteger.ZERO;
        sendInitMessage();
    }

    Set<EndpointId> getSupportedEndpoints() {
        return ImmutableSet.of(EndpointId.PUT_BYTES);
    }

    private boolean isEndpointIdSupported(EndpointId endpointId) {
        return getSupportedEndpoints().contains(endpointId);
    }

    public boolean onReceive(ProtocolMessage message) {
        Trace.debug(TAG, "Got protocol message while in state: " + this.mState);
        if (!isEndpointIdSupported(EndpointId.fromCode(message.getEndpointId()))) {
            return false;
        }
        cancelTimeout();
        PblInboundPutBytesMessage putBytesMessage = new PblInboundPutBytesMessage(message);
        if (putBytesMessage.getResponse().equals(PutBytesResponse.NACK)) {
            Trace.warning(TAG, "Received a put-bytes NACK");
            this.mInstallResult = getInstallErrorByState();
            abortTransfer();
            return true;
        }
        Listener listener = getListener();
        switch (AnonymousClass2.$SwitchMap$com$getpebble$android$framework$endpoint$PutBytesEndpoint$State[this.mState.ordinal()]) {
            case SMTPMessage.RETURN_FULL /*1*/:
                this.mCookie = putBytesMessage.getCookie();
                this.mState = State.SENDING_DATA;
                sendPutMessage();
                break;
            case SMTPMessage.RETURN_HDRS /*2*/:
                sendPutMessage();
                break;
            case ListInfo.INDETERMINATE /*3*/:
                this.mState = State.WAITING_FOR_INSTALL;
                this.mInstallResult = InstallResult.OK;
                if (listener != null) {
                    listener.transferComplete(this.mCookie);
                    break;
                }
                break;
            case SMTPMessage.NOTIFY_DELAY /*4*/:
                if (listener != null) {
                    boolean wasInstalling = this.mAbortedState != null && this.mAbortedState.equals(State.INSTALLING);
                    if (wasInstalling) {
                        listener.installFailed(this.mInstallResult);
                    } else {
                        listener.transferFailed(this.mInstallResult);
                    }
                }
                cleanup();
                break;
            case R.styleable.WalletFragmentStyle_maskedWalletDetailsHeaderTextAppearance /*5*/:
                if (listener != null) {
                    listener.installComplete(this.mCookie);
                    break;
                }
                break;
            default:
                Trace.warning(TAG, "Got message in unexpected state: " + this.mState + ", failing.");
                this.mState = State.IDLE;
                abortTransfer();
                break;
        }
        return true;
    }

    public boolean install(UnsignedInteger cookie) {
        this.mState = State.INSTALLING;
        if (getMessageSender().sendMessage(PblOutboundPutBytesMessage.createInstall(cookie))) {
            Trace.debug(TAG, "install(" + cookie.toString() + ")");
            startTimeout();
            return true;
        }
        Trace.debug(TAG, "Failed to send install message");
        return false;
    }

    private InstallResult getInstallErrorByState() {
        switch (AnonymousClass2.$SwitchMap$com$getpebble$android$framework$endpoint$PutBytesEndpoint$State[this.mState.ordinal()]) {
            case SMTPMessage.RETURN_FULL /*1*/:
                return InstallResult.ACK_FAILED;
            case SMTPMessage.RETURN_HDRS /*2*/:
                return InstallResult.LOAD_FAILED;
            case ListInfo.INDETERMINATE /*3*/:
                return InstallResult.INVALID_CRC;
            default:
                return InstallResult.UNKNOWN_ERROR;
        }
    }

    private void sendInitMessage() {
        getMessageSender().sendMessage(PblOutboundPutBytesMessage.createInit(this.mSize, this.mInstallType, this.mAppBank, this.mName));
        startTimeout();
        Trace.debug(TAG, "Sending init message for size: " + this.mSize + ", installType: " + this.mInstallType + ", bank: " + this.mAppBank + ", name: " + this.mName);
        this.mState = State.WAITING_FOR_COOKIE;
    }

    private void sendPutMessage() {
        byte[] payload = new byte[2000];
        try {
            int payloadSize = this.mInputStream.read(payload);
            if (payloadSize > 0) {
                this.mStm32Crc.addBytes(payload, payloadSize);
                this.mBytesTransferred = this.mBytesTransferred.plus(UnsignedInteger.fromIntBits(payloadSize));
                PblOutboundPutBytesMessage message = PblOutboundPutBytesMessage.createPut(this.mCookie, UnsignedInteger.fromIntBits(payloadSize), payload);
                Listener listener = getListener();
                if (listener != null) {
                    listener.progressUpdated(this.mBytesTransferred, this.mSize);
                }
                getMessageSender().sendMessage(message);
                startTimeout();
            } else if (payloadSize >= 0 || this.mBytesTransferred.compareTo(this.mSize) >= 0) {
                closeInputStream();
                sendCommitMessage();
            } else {
                this.mInstallResult = InstallResult.UNKNOWN_ERROR;
                abortTransfer();
            }
        } catch (IOException e) {
            this.mInstallResult = InstallResult.UNKNOWN_ERROR;
            abortTransfer();
        }
    }

    private void closeInputStream() {
        if (this.mInputStream != null) {
            try {
                this.mInputStream.close();
            } catch (IOException e) {
                Trace.warning(TAG, "Failed to close put bytes stream");
            }
            this.mInputStream = null;
        }
    }

    private void sendCommitMessage() {
        Trace.debug(TAG, "sendCommitMessage()");
        UnsignedInteger crc = UnsignedInteger.fromIntBits(this.mStm32Crc.finalizeCrc());
        if (crc.equals(this.mExpectedCrc)) {
            getMessageSender().sendMessage(PblOutboundPutBytesMessage.createCommit(this.mCookie, crc));
            startTimeout();
            this.mState = State.COMMIT_SENT;
            return;
        }
        this.mInstallResult = InstallResult.INVALID_CRC;
        abortTransfer();
    }

    private void abortTransfer() {
        Trace.debug(TAG, "abortTransfer()");
        if (this.mCookie != null) {
            Trace.debug(TAG, "Cancelling");
            this.mAbortedState = this.mState;
            this.mState = State.CANCELLED;
            getMessageSender().sendMessage(PblOutboundPutBytesMessage.createAbort(this.mCookie));
            startTimeout();
            return;
        }
        Trace.debug(TAG, "Cannot cancel gracefully; cleaning up");
        Listener listener = getListener();
        if (listener != null) {
            if (this.mState.equals(State.INSTALLING)) {
                listener.installFailed(this.mInstallResult);
            } else {
                listener.transferFailed(this.mInstallResult);
            }
        }
        cleanup();
    }

    private void cleanup() {
        cancelTimeout();
        this.mState = State.IDLE;
        this.mAbortedState = null;
        closeInputStream();
        this.mName = null;
        this.mSize = null;
        this.mExpectedCrc = null;
        this.mAppBank = -1;
        this.mInstallType = null;
        this.mCookie = null;
        this.mStm32Crc = null;
        this.mBytesTransferred = null;
    }
}
